Micron Document
welo git mirrors

Node / public / reticulum / files / Examples / ExampleInterface.py

Displaying Raw • Download

Examples/ExampleInterface.py 51b7dc7cd4b793ead979dfa8d1ddaeaa2ca0ae61 (51b7dc7c) Text, 11.37 KB

T8b949e# This example illustrates creating a custom interface
T8b949e# definition, that can be loaded and used by Reticulum at
T8b949e# runtime. Any number of custom interfaces can be created
T8b949e# and loaded. To use the interface place it in the folder
T8b949e# ~/.reticulum/interfaces, and add an interface entry to
T8b949e# your Reticulum configuration file similar to this:

T8b949e# [[Example Custom Interface]]
T8b949e# type = ExampleInterface
T8b949e# enabled = no
T8b949e# mode = gateway
T8b949e# port = /dev/ttyUSB0
T8b949e# speed = 115200
T8b949e# databits = 8
T8b949e# parity = none
T8b949e# stopbits = 1

Tff7b72from T7ee787time Tff7b72import Te6edf3sleep
Tff7b72import T7ee787sys
Tff7b72import T7ee787threading
Tff7b72import T7ee787time

T8b949e# This HDLC helper class is used by the interface
T8b949e# to delimit and packetize data over the physical
T8b949e# medium - in this case a serial connection.
Tff7b72class T56d364HDLCTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e# This example interface packetizes data using
T8b949e# simplified HDLC framing, similar to PPP
Te6edf3FLAG Tff7b72= T79c0ff0x7E
Te6edf3ESC Tff7b72= T79c0ff0x7D
Te6edf3ESC_MASK Tff7b72= T79c0ff0x20

Tf0883e@staticmethod
Tff7b72def Td2a8ffescapeTb4b4b4(Te6edf3dataTb4b4b4)Tb4b4b4:
Te6edf3data Tff7b72= Te6edf3dataTff7b72.Td2a8ffreplaceTb4b4b4(Tffa657bytesTb4b4b4(Tb4b4b4[Te6edf3HDLCTff7b72.Td2a8ffESCTb4b4b4]Tb4b4b4)Tb4b4b4, Tffa657bytesTb4b4b4(Tb4b4b4[Te6edf3HDLCTff7b72.Td2a8ffESCTb4b4b4, Te6edf3HDLCTff7b72.Td2a8ffESCTff7b72^Te6edf3HDLCTff7b72.Td2a8ffESC_MASKTb4b4b4]Tb4b4b4)Tb4b4b4)
Te6edf3data Tff7b72= Te6edf3dataTff7b72.Td2a8ffreplaceTb4b4b4(Tffa657bytesTb4b4b4(Tb4b4b4[Te6edf3HDLCTff7b72.Td2a8ffFLAGTb4b4b4]Tb4b4b4)Tb4b4b4, Tffa657bytesTb4b4b4(Tb4b4b4[Te6edf3HDLCTff7b72.Td2a8ffESCTb4b4b4, Te6edf3HDLCTff7b72.Td2a8ffFLAGTff7b72^Te6edf3HDLCTff7b72.Td2a8ffESC_MASKTb4b4b4]Tb4b4b4)Tb4b4b4)
Tff7b72return Te6edf3data

T8b949e# Let's define our custom interface class. It must
T8b949e# be a sub-class of the RNS "Interface" class.
Tff7b72class T56d364ExampleInterfaceTb4b4b4(Te6edf3InterfaceTb4b4b4)Tb4b4b4:
T8b949e# All interface classes must define a default
T8b949e# IFAC size, used in IFAC setup when the user
T8b949e# has not specified a custom IFAC size. This
T8b949e# option is specified in bytes.
Te6edf3DEFAULT_IFAC_SIZE Tff7b72= T79c0ff8

T8b949e# The following properties are local to this
T8b949e# particular interface implementation.
Te6edf3owner Tff7b72= Tff7b72None
Te6edf3port Tff7b72= Tff7b72None
Te6edf3speed Tff7b72= Tff7b72None
Te6edf3databits Tff7b72= Tff7b72None
Te6edf3parity Tff7b72= Tff7b72None
Te6edf3stopbits Tff7b72= Tff7b72None
Te6edf3serial Tff7b72= Tff7b72None

T8b949e# All Reticulum interfaces must have an __init__
T8b949e# method that takes 2 positional arguments:
T8b949e# The owner RNS Transport instance, and a dict
T8b949e# of configuration values.
Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3ownerTb4b4b4, Te6edf3configurationTb4b4b4)Tb4b4b4:

T8b949e# The following lines demonstrate handling
T8b949e# potential dependencies required for the
T8b949e# interface to function correctly.
Tff7b72import T7ee787importlib
Tff7b72if Te6edf3importlibTff7b72.Td2a8ffutilTff7b72.Td2a8fffind_specTb4b4b4(Ta5d6ff'Ta5d6ffserialTa5d6ff'Tb4b4b4) Tff7b72!= Tff7b72NoneTb4b4b4:
Tff7b72import T7ee787serial
Tff7b72elseTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffUsing this interface requires a serial communication module to be installed.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_CRITICALTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffYou can install one with the command: python3 -m pip install pyserialTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_CRITICALTb4b4b4)
Te6edf3RNSTff7b72.Td2a8ffpanicTb4b4b4(Tb4b4b4)

T8b949e# We start out by initialising the super-class
Tffa657superTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ff__init__Tb4b4b4(Tb4b4b4)

T8b949e# To make sure the configuration data is in the
T8b949e# correct format, we parse it through the following
T8b949e# method on the generic Interface class. This step
T8b949e# is required to ensure compatibility on all the
T8b949e# platforms that Reticulum supports.
Te6edf3ifconf Tff7b72= Te6edf3InterfaceTff7b72.Td2a8ffget_config_objTb4b4b4(Te6edf3configurationTb4b4b4)

T8b949e# Read the interface name from the configuration
T8b949e# and set it on our interface instance.
Te6edf3name Tff7b72= Te6edf3ifconfTb4b4b4[Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ffname Tff7b72= Te6edf3name

T8b949e# We read configuration parameters from the supplied
T8b949e# configuration data, and provide default values in
T8b949e# case any are missing.
Te6edf3port Tff7b72= Te6edf3ifconfTb4b4b4[Ta5d6ff"Ta5d6ffportTa5d6ff"Tb4b4b4] Tff7b72if Ta5d6ff"Ta5d6ffportTa5d6ff" Tff7b72in Te6edf3ifconf Tff7b72else Tff7b72None
Te6edf3speed Tff7b72= Tffa657intTb4b4b4(Te6edf3ifconfTb4b4b4[Ta5d6ff"Ta5d6ffspeedTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72if Ta5d6ff"Ta5d6ffspeedTa5d6ff" Tff7b72in Te6edf3ifconf Tff7b72else T79c0ff9600
Te6edf3databits Tff7b72= Tffa657intTb4b4b4(Te6edf3ifconfTb4b4b4[Ta5d6ff"Ta5d6ffdatabitsTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72if Ta5d6ff"Ta5d6ffdatabitsTa5d6ff" Tff7b72in Te6edf3ifconf Tff7b72else T79c0ff8
Te6edf3parity Tff7b72= Te6edf3ifconfTb4b4b4[Ta5d6ff"Ta5d6ffparityTa5d6ff"Tb4b4b4] Tff7b72if Ta5d6ff"Ta5d6ffparityTa5d6ff" Tff7b72in Te6edf3ifconf Tff7b72else Ta5d6ff"Ta5d6ffNTa5d6ff"
Te6edf3stopbits Tff7b72= Tffa657intTb4b4b4(Te6edf3ifconfTb4b4b4[Ta5d6ff"Ta5d6ffstopbitsTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72if Ta5d6ff"Ta5d6ffstopbitsTa5d6ff" Tff7b72in Te6edf3ifconf Tff7b72else T79c0ff1

T8b949e# In case no port is specified, we abort setup by
T8b949e# raising an exception.
Tff7b72if Te6edf3port Tff7b72== Tff7b72NoneTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffNo port specified for Tffd700{Tff7b72selfTffd700}Ta5d6ff"Tb4b4b4)

T8b949e# All interfaces must supply a hardware MTU value
T8b949e# to the RNS Transport instance. This value should
T8b949e# be the maximum data packet payload size that the
T8b949e# underlying medium is capable of handling in all
T8b949e# cases without any segmentation.
Tff7b72selfTff7b72.Td2a8ffHW_MTU Tff7b72= T79c0ff564

T8b949e# We initially set the "online" property to false,
T8b949e# since the interface has not actually been fully
T8b949e# initialised and connected yet.
Tff7b72selfTff7b72.Td2a8ffonline Tff7b72= Tff7b72False

T8b949e# In this case, we can also set the indicated bit-
T8b949e# rate of the interface to the serial port speed.
Tff7b72selfTff7b72.Td2a8ffbitrate Tff7b72= Te6edf3speed
T8b949e# Configure internal properties on the interface
T8b949e# according to the supplied configuration.
Tff7b72selfTff7b72.Td2a8ffpyserial Tff7b72= Te6edf3serial
Tff7b72selfTff7b72.Td2a8ffserial Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffowner Tff7b72= Te6edf3owner
Tff7b72selfTff7b72.Td2a8ffport Tff7b72= Te6edf3port
Tff7b72selfTff7b72.Td2a8ffspeed Tff7b72= Te6edf3speed
Tff7b72selfTff7b72.Td2a8ffdatabits Tff7b72= Te6edf3databits
Tff7b72selfTff7b72.Td2a8ffparity Tff7b72= Te6edf3serialTff7b72.Td2a8ffPARITY_NONE
Tff7b72selfTff7b72.Td2a8ffstopbits Tff7b72= Te6edf3stopbits
Tff7b72selfTff7b72.Td2a8fftimeout Tff7b72= T79c0ff100

Tff7b72if Te6edf3parityTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffeTa5d6ff" Tff7b72or Te6edf3parityTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffevenTa5d6ff"Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffparity Tff7b72= Te6edf3serialTff7b72.Td2a8ffPARITY_EVEN

Tff7b72if Te6edf3parityTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffoTa5d6ff" Tff7b72or Te6edf3parityTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffoddTa5d6ff"Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffparity Tff7b72= Te6edf3serialTff7b72.Td2a8ffPARITY_ODD

T8b949e# Since all required parameters are now configured,
T8b949e# we will try opening the serial port.
Tff7b72tryTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffopen_portTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffCould not open serial port for interface Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tff7b72raise Te6edf3e

T8b949e# If opening the port succeeded, run any post-open
T8b949e# configuration required.
Tff7b72if Tff7b72selfTff7b72.Td2a8ffserialTff7b72.Td2a8ffis_openTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffconfigure_deviceTb4b4b4(Tb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149IOErrorTb4b4b4(Ta5d6ff"Ta5d6ffCould not open serial portTa5d6ff"Tb4b4b4)

T8b949e# Open the serial port with supplied configuration
T8b949e# parameters and store a reference to the open port.
Tff7b72def Td2a8ffopen_portTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffOpening serial port Ta5d6ff"Tff7b72+Tff7b72selfTff7b72.Td2a8ffportTff7b72+Ta5d6ff"Ta5d6ff...Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_VERBOSETb4b4b4)
Tff7b72selfTff7b72.Td2a8ffserial Tff7b72= Tff7b72selfTff7b72.Td2a8ffpyserialTff7b72.Td2a8ffSerialTb4b4b4(
Te6edf3port Tff7b72= Tff7b72selfTff7b72.Td2a8ffportTb4b4b4,
Te6edf3baudrate Tff7b72= Tff7b72selfTff7b72.Td2a8ffspeedTb4b4b4,
Te6edf3bytesize Tff7b72= Tff7b72selfTff7b72.Td2a8ffdatabitsTb4b4b4,
Te6edf3parity Tff7b72= Tff7b72selfTff7b72.Td2a8ffparityTb4b4b4,
Te6edf3stopbits Tff7b72= Tff7b72selfTff7b72.Td2a8ffstopbitsTb4b4b4,
Te6edf3xonxoff Tff7b72= Tff7b72FalseTb4b4b4,
Te6edf3rtscts Tff7b72= Tff7b72FalseTb4b4b4,
Te6edf3timeout Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3inter_byte_timeout Tff7b72= Tff7b72NoneTb4b4b4,
Te6edf3write_timeout Tff7b72= Tff7b72NoneTb4b4b4,
Te6edf3dsrdtr Tff7b72= Tff7b72FalseTb4b4b4,
Tb4b4b4)

T8b949e# The only thing required after opening the port
T8b949e# is to wait a small amount of time for the
T8b949e# hardware to initialise and then start a thread
T8b949e# that reads any incoming data from the device.
Tff7b72def Td2a8ffconfigure_deviceTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3sleepTb4b4b4(T79c0ff0.5Tb4b4b4)
Te6edf3thread Tff7b72= Te6edf3threadingTff7b72.Td2a8ffThreadTb4b4b4(Te6edf3targetTff7b72=Tff7b72selfTff7b72.Td2a8ffread_loopTb4b4b4)
Te6edf3threadTff7b72.Td2a8ffdaemon Tff7b72= Tff7b72True
Te6edf3threadTff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffonline Tff7b72= Tff7b72True
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffSerial port Ta5d6ff"Tff7b72+Tff7b72selfTff7b72.Td2a8ffportTff7b72+Ta5d6ff"Ta5d6ff is now openTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_VERBOSETb4b4b4)


T8b949e# This method will be called from our read-loop
T8b949e# whenever a full packet has been received over
T8b949e# the underlying medium.
Tff7b72def Td2a8ffprocess_incomingTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3dataTb4b4b4)Tb4b4b4:
T8b949e# Update our received bytes counter
Tff7b72selfTff7b72.Td2a8ffrxb Tff7b72+Tff7b72= Tffa657lenTb4b4b4(Te6edf3dataTb4b4b4)

T8b949e# And send the data packet to the Transport
T8b949e# instance for processing.
Tff7b72selfTff7b72.Td2a8ffownerTff7b72.Td2a8ffinboundTb4b4b4(Te6edf3dataTb4b4b4, Tff7b72selfTb4b4b4)

T8b949e# The running Reticulum Transport instance will
T8b949e# call this method on the interface whenever the
T8b949e# interface must transmit a packet.
Tff7b72def Td2a8ffprocess_outgoingTb4b4b4(Tff7b72selfTb4b4b4,Te6edf3dataTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffonlineTb4b4b4:
T8b949e# First, escape and packetize the data
T8b949e# according to HDLC framing.
Te6edf3data Tff7b72= Tffa657bytesTb4b4b4(Tb4b4b4[Te6edf3HDLCTff7b72.Td2a8ffFLAGTb4b4b4]Tb4b4b4)Tff7b72+Te6edf3HDLCTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3dataTb4b4b4)Tff7b72+Tffa657bytesTb4b4b4(Tb4b4b4[Te6edf3HDLCTff7b72.Td2a8ffFLAGTb4b4b4]Tb4b4b4)

T8b949e# Then write the framed data to the port
Te6edf3written Tff7b72= Tff7b72selfTff7b72.Td2a8ffserialTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3dataTb4b4b4)

T8b949e# Update the transmitted bytes counter
T8b949e# and ensure that all data was written
Tff7b72selfTff7b72.Td2a8fftxb Tff7b72+Tff7b72= Tffa657lenTb4b4b4(Te6edf3dataTb4b4b4)
Tff7b72if Te6edf3written Tff7b72!= Tffa657lenTb4b4b4(Te6edf3dataTb4b4b4)Tb4b4b4:
Tff7b72raise Tf85149IOErrorTb4b4b4(Ta5d6ff"Ta5d6ffSerial interface only wrote Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3writtenTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff bytes of Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tffa657lenTb4b4b4(Te6edf3dataTb4b4b4)Tb4b4b4)Tb4b4b4)

T8b949e# This read loop runs in a thread and continously
T8b949e# receives bytes from the underlying serial port.
T8b949e# When a full packet has been received, it will
T8b949e# be sent to the process_incoming methed, which
T8b949e# will in turn pass it to the Transport instance.
Tff7b72def Td2a8ffread_loopTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3in_frame Tff7b72= Tff7b72False
Te6edf3escape Tff7b72= Tff7b72False
Te6edf3data_buffer Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff"
Te6edf3last_read_ms Tff7b72= Tffa657intTb4b4b4(Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tff7b72*T79c0ff1000Tb4b4b4)

Tff7b72while Tff7b72selfTff7b72.Td2a8ffserialTff7b72.Td2a8ffis_openTb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffserialTff7b72.Td2a8ffin_waitingTb4b4b4:
Te6edf3byte Tff7b72= Tffa657ordTb4b4b4(Tff7b72selfTff7b72.Td2a8ffserialTff7b72.Td2a8ffreadTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4)
Te6edf3last_read_ms Tff7b72= Tffa657intTb4b4b4(Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tff7b72*T79c0ff1000Tb4b4b4)

Tff7b72if Tb4b4b4(Te6edf3in_frame Tff7b72and Te6edf3byte Tff7b72== Te6edf3HDLCTff7b72.Td2a8ffFLAGTb4b4b4)Tb4b4b4:
Te6edf3in_frame Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8ffprocess_incomingTb4b4b4(Te6edf3data_bufferTb4b4b4)
Tff7b72elif Tb4b4b4(Te6edf3byte Tff7b72== Te6edf3HDLCTff7b72.Td2a8ffFLAGTb4b4b4)Tb4b4b4:
Te6edf3in_frame Tff7b72= Tff7b72True
Te6edf3data_buffer Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff"
Tff7b72elif Tb4b4b4(Te6edf3in_frame Tff7b72and Tffa657lenTb4b4b4(Te6edf3data_bufferTb4b4b4) Tff7b72< Tff7b72selfTff7b72.Td2a8ffHW_MTUTb4b4b4)Tb4b4b4:
Tff7b72if Tb4b4b4(Te6edf3byte Tff7b72== Te6edf3HDLCTff7b72.Td2a8ffESCTb4b4b4)Tb4b4b4:
Te6edf3escape Tff7b72= Tff7b72True
Tff7b72elseTb4b4b4:
Tff7b72if Tb4b4b4(Te6edf3escapeTb4b4b4)Tb4b4b4:
Tff7b72if Tb4b4b4(Te6edf3byte Tff7b72== Te6edf3HDLCTff7b72.Td2a8ffFLAG Tff7b72^ Te6edf3HDLCTff7b72.Td2a8ffESC_MASKTb4b4b4)Tb4b4b4:
Te6edf3byte Tff7b72= Te6edf3HDLCTff7b72.Td2a8ffFLAG
Tff7b72if Tb4b4b4(Te6edf3byte Tff7b72== Te6edf3HDLCTff7b72.Td2a8ffESC Tff7b72^ Te6edf3HDLCTff7b72.Td2a8ffESC_MASKTb4b4b4)Tb4b4b4:
Te6edf3byte Tff7b72= Te6edf3HDLCTff7b72.Td2a8ffESC
Te6edf3escape Tff7b72= Tff7b72False
Te6edf3data_buffer Tff7b72= Te6edf3data_bufferTff7b72+Tffa657bytesTb4b4b4(Tb4b4b4[Te6edf3byteTb4b4b4]Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3time_since_last Tff7b72= Tffa657intTb4b4b4(Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tff7b72*T79c0ff1000Tb4b4b4) Tff7b72- Te6edf3last_read_ms
Tff7b72if Tffa657lenTb4b4b4(Te6edf3data_bufferTb4b4b4) Tff7b72> T79c0ff0 Tff7b72and Te6edf3time_since_last Tff7b72> Tff7b72selfTff7b72.Td2a8fftimeoutTb4b4b4:
Te6edf3data_buffer Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff"
Te6edf3in_frame Tff7b72= Tff7b72False
Te6edf3escape Tff7b72= Tff7b72False
Te6edf3sleepTb4b4b4(T79c0ff0.08Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffonline Tff7b72= Tff7b72False
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffA serial port error occurred, the contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThe interface Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tff7b72selfTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff experienced an unrecoverable error and is now offline.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tff7b72if Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffpanic_on_interface_errorTb4b4b4:
Te6edf3RNSTff7b72.Td2a8ffpanicTb4b4b4(Tb4b4b4)

Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffReticulum will attempt to reconnect the interface periodically.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)

Tff7b72selfTff7b72.Td2a8ffonline Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8ffserialTff7b72.Td2a8ffcloseTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffreconnect_portTb4b4b4(Tb4b4b4)

T8b949e# This method handles serial port disconnects.
Tff7b72def Td2a8ffreconnect_portTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72while Tff7b72not Tff7b72selfTff7b72.Td2a8ffonlineTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff5Tb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffAttempting to reconnect serial port Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tff7b72selfTff7b72.Td2a8ffportTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff for Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tff7b72selfTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff...Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_VERBOSETb4b4b4)
Tff7b72selfTff7b72.Td2a8ffopen_portTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72selfTff7b72.Td2a8ffserialTff7b72.Td2a8ffis_openTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffconfigure_deviceTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffError while reconnecting port, the contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)

Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffReconnected serial port for Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4)

T8b949e# Signal to Reticulum that this interface should
T8b949e# not perform any ingress limiting.
Tff7b72def Td2a8ffshould_ingress_limitTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False

T8b949e# We must provide a string representation of this
T8b949e# interface, that is used whenever the interface
T8b949e# is printed in logs or external programs.
Tff7b72def Tff7b72__str__Tb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ffExampleInterface[Ta5d6ff"Tff7b72+Tff7b72selfTff7b72.Td2a8ffnameTff7b72+Ta5d6ff"Ta5d6ff]Ta5d6ff"

T8b949e# Finally, register the defined interface class as the
T8b949e# target class for Reticulum to use as an interface
Te6edf3interface_class Tff7b72= Te6edf3ExampleInterface

Served by rngit 1.4.2 - Generated in 0.05s